<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <style>
      div {
        width: 90px;
        height: 90px;
      }
      .red {
        background-color: red;
      }
      .green {
        background-color: green;
      }
      .yellow {
        background-color: yellow;
      }
      .skyblue {
        background-color: skyblue;
      }
    </style>
  </head>
  <body>
    <div class="red">red</div>
    <div class="yellow">yellow</div>
    <div class="green">green</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <div class="skyblue">skyblue</div>
    <script>
      let divs = document.querySelectorAll("div");
      let startDragDom = null;
      let endDropDom = null;
      let startPosition = {};
      let endPosition = {};
      let timer = null;

      let flag = true;
      let timerFlag = true;
      new Array().map.call(divs, (val, index) => {
        val.setAttribute("draggable", true);
        val.setAttribute("index", index);
        val.ondragstart = startDrag;
        val.ondrop = endTargetDom;

        val.ondragover = function (e) {
          e.preventDefault();
          // 鼠标松开需要放到的元素
          endDropDom = e.target;
          endPosition = endDropDom.getBoundingClientRect().y;

          /*
          第一种方法：
          获取目标元素的和拖拽元素的索引
           目标元素>拖拽元素 插入到目标元素下面元素的前面
           反之插入目标元素的前面
          */
          /*
          第二种方法：
          1.看拖拽元素的索引 开始索引和结束索引之间的元素需要移动
          2.目标索引>拖拽索引 向上移动  反之 向下移动
          */

          let dropIndex = startDragDom.getAttribute("index") * 1;
          let targetIndex = endDropDom.getAttribute("index") * 1;
          let arr = [];
          if (flag) {
            window.clearTimeout(timer);
          }
          if (startDragDom === endDropDom) return;
          if (targetIndex > dropIndex) {
            for (let i = dropIndex + 1; i <= targetIndex; i++) {
              arr.push(i);
            }
            addSlideAndClearTrasition(
              arr,
              "-90px",
              startDragDom,
              endDropDom.nextSibling
            );
          } else {
            for (let i = targetIndex; i < dropIndex; i++) {
              arr.push(i);
            }
            addSlideAndClearTrasition(arr, "90px", startDragDom, endDropDom);
          }
        };
      });
      function startDrag(e) {
        // 需要拖拽的元素
        startDragDom = e.target;
        startPosition = startDragDom.getBoundingClientRect().y;
      }
      function endTargetDom(e) {}
      function resetDom() {
        new Array().map.call(document.querySelectorAll("div"), (val, index) => {
          val.setAttribute("index", index);
        });
        timerFlag = true;
      }
      // 滑块添加滑动效果 过度秒数后 刷新滑块顺序
      function addSlideAndClearTrasition(arr, transY, insertDom, insertPlace) {
        let moveDom = [];
        if (flag) {
          flag = false;
          [].map.call(divs, (val) => {
            let index = val.getAttribute("index");
            if (arr.indexOf(index * 1) !== -1) {
              moveDom.push(val);
              val.style.transition = "all 0.1s";
              val.style.transform = `translate(0,${transY})`;
            }
          });
        }
        if (timerFlag) {
          timerFlag = false;
          timer = setTimeout(() => {
            console.log("定时器");
            moveDom.map((val) => {
              val.style.transition = "none";
              val.style.transform = "translate(0,0)";
            });
            endDropDom.parentNode.insertBefore(insertDom, insertPlace);
            flag = true;
            resetDom();
          }, 100);
        }
      }
    </script>
  </body>
</html>
